//---------------------------------------------------------------------------------------------------------------------------------------------------
// <copyright file="MouseControl.cs" company="DarkWynter Studios">
//     Copyright (C)2007 DarkWynter Studios.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------

namespace DarkWynter.Engine.Controllers
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Input;
    using System.Diagnostics;

    //using DarkWynter.Stream;
    //using DarkWynter.Engine.ObjectLib;
    //using DarkWynter.Engine.Menus;

    //using Globals;
    #endregion

    /// <summary>
    /// Mouse event class for mapping a Mouse button/motion to an event
    /// </summary>
    public class MouseControl
    {
        // Time delay between key presses to avoid double input
        private int KEY_TIMER_MAX_MILLI = 10;

        private Stopwatch controlTimer = new Stopwatch();

        private float MOUSE_ROTATION_SCALE = 0.005f;
        private float lastMouseX, lastMouseY;
        private int windowHeight, windowWidth;          // Game window Height and Width for resetting the Mouse position
        private int lastMouseWheelPos = 0;              // Position of mouse wheel on element list

        /// <summary>
        /// On click delegate type
        /// </summary>
        /// <param name="args">Controller boolean event arguments</param>
        public delegate void OnClickHandler(ControllerBoolEventArgs args);
        private event OnClickHandler click;

        /// <summary>
        /// On motion delegate type
        /// </summary>
        /// <param name="args">Controller vector2 event arguments</param>
        public delegate void OnMotionHandler(ControllerVec2EventArgs args);
        private event OnMotionHandler motion;

        /// <summary>
        /// On scroll delegate type
        /// </summary>
        /// <param name="args">Controller integer event arguments</param>
        public delegate void OnScrollHandler(ControllerIntEventArgs args);
        private event OnScrollHandler scroll;

        /// <summary>
        /// Type of control for this event
        /// </summary>
        public ControlType controlType;

        /// <summary>
        /// Click constructor
        /// </summary>
        /// <param name="type">Click control type</param>
        /// <param name="onClickHandler">Click handler</param>
        /// <param name="timerValue">Time delay between multiple invocations</param>
        public MouseControl(ControlType type, OnClickHandler onClickHandler, int timerValue)
        {
            controlType = type;
            click += new OnClickHandler(onClickHandler);
            controlTimer.Start();
            KEY_TIMER_MAX_MILLI = timerValue;
        }
        /// <summary>
        /// Motion constructor
        /// </summary>
        /// <param name="type">Motion control type</param>
        /// <param name="onMotionHandler">Motion handler</param>
        /// <param name="timerValue">Time delay between multiple invocations</param>
        public MouseControl(ControlType type, OnMotionHandler onMotionHandler, int timerValue)
        {
            controlType = type;
            motion += new OnMotionHandler(onMotionHandler);
            controlTimer.Start();
            KEY_TIMER_MAX_MILLI = timerValue;

            lastMouseX = Mouse.GetState().X;
            lastMouseY = Mouse.GetState().Y;
        }
        /// <summary>
        /// Scroll constructor
        /// </summary>
        /// <param name="type">Scroll control type</param>
        /// <param name="onScrollHandler">Scroll handler</param>
        /// <param name="timerValue">Time delay between multiple invocations</param>
        public MouseControl(ControlType type, OnScrollHandler onScrollHandler, int timerValue)
        {
            controlType = type;
            scroll += new OnScrollHandler(onScrollHandler);
            controlTimer.Start();
            KEY_TIMER_MAX_MILLI = timerValue;

            lastMouseWheelPos = Mouse.GetState().ScrollWheelValue;
        }

        /// <summary>
        /// Update Method
        /// </summary>
        /// <param name="mouseState">Updated mouse state</param>
        /// <param name="objectLibrary">Object Library</param>
        /// <param name="menuSystem">Menu System</param>
        public void Update(MouseState mouseState, ref List<object> argObjects)
        {
            // Check double-input timer
            if (controlTimer.ElapsedMilliseconds > KEY_TIMER_MAX_MILLI)
            {
                // Reset timer
                controlTimer.Reset();
                controlTimer.Start();

                // Get updated window dimensions
                windowWidth = ControllerManager.clientSize.X;
                windowHeight = ControllerManager.clientSize.Y;

                #region Movement Section
                // Calculate Mouse movement since last frame
                if (controlType == ControlType.Motion)
                {
                    // If mouse is in the window
                    if (mouseState.X > 0 && mouseState.X < windowWidth - 1 &&
                        mouseState.Y > 0 && mouseState.Y < windowHeight - 1)
                    {
                        // Find change in mouse position since last frame
                        float diffX = mouseState.X - windowWidth / 2;
                        float diffY = mouseState.Y - windowHeight / 2;

                        // Scale difference 
                        Vector2 mouseRotation = new Vector2(
                             MOUSE_ROTATION_SCALE * diffX,
                             -MOUSE_ROTATION_SCALE * diffY);

                        // Set up Event
                        ControllerVec2EventArgs args = new ControllerVec2EventArgs(mouseRotation, ref argObjects);
                        
                        // Set mouse back to center of screen    
                        Mouse.SetPosition(windowWidth / 2, windowHeight / 2);

                        if (motion != null)
                        {
                            motion(args);
                        }
                    }
                }
                #endregion

                #region Click Section
                // Left Button Check
                else if (controlType == ControlType.LeftButton)
                {
                    if (mouseState.LeftButton == ButtonState.Pressed)
                    {
                        // Reset timer
                        controlTimer.Reset();
                        controlTimer.Start();

                        if (click != null)
                        {
                            click(new ControllerBoolEventArgs(true, ref argObjects));
                        }
                    }
                }

                // Right Button Check
                else if (controlType == ControlType.RightButton)
                {
                    if (mouseState.RightButton == ButtonState.Pressed)
                    {
                        // Reset timer
                        controlTimer.Reset();
                        controlTimer.Start();

                        if (click != null)
                        {
                            click(new ControllerBoolEventArgs(true, ref argObjects));
                        }
                    }
                }

                // Middle Button Click
                else if (controlType == ControlType.MiddleButton)
                {
                    if (mouseState.MiddleButton == ButtonState.Pressed)
                    {
                        // Reset timer
                        controlTimer.Reset();
                        controlTimer.Start();

                        if (click != null)
                        {
                            click(new ControllerBoolEventArgs(true, ref argObjects));
                        }
                    }
                }
                #endregion

                #region Scroll Section
                // Scroll Check
                else if (controlType == ControlType.ScrollWheel)
                {
                    if (mouseState.ScrollWheelValue != lastMouseWheelPos)
                    {
                        // Reset timer
                        controlTimer.Reset();
                        controlTimer.Start();

                        int diff;
                        if (mouseState.ScrollWheelValue > lastMouseWheelPos)
                        {
                            diff = 1;
                        }
                        else
                        {
                            diff = -1;
                        }
                        lastMouseWheelPos = mouseState.ScrollWheelValue;

                        if (scroll != null)
                        {
                            scroll(new ControllerIntEventArgs(diff, ref argObjects));
                        }
                    }
                }
                #endregion
            }
        }
    }
}
